package com.hh.game.service.gateway.webscoket;

import com.hh.game.common.base.exception.ApplicationStartException;
import com.hh.game.service.gateway.config.TotalConfig;
import com.hh.game.service.gateway.exception.InitErrorException;
import com.hh.game.service.gateway.filter.ip.RateLimitConfig;
import com.hh.game.service.gateway.pool.GatewayWorkPool;
import com.hh.game.service.gateway.webscoket.config.WebSocketServerConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Component
@Order(value = Integer.MIN_VALUE)
public class WebSocketServer implements ApplicationRunner {
    private Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    private Channel channel;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;

    @Autowired
    private TotalConfig totalConfig;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        start();
    }

    public void start() throws Exception {
        WebSocketServerConfig websocketServerConfig = totalConfig.getWebSocketServerConfig();

        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup(websocketServerConfig.getWorkLoopGroupThreads());
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new WebSocketServerInitializer(totalConfig));

        ChannelFuture future = bootstrap.bind(websocketServerConfig.getPort()).sync();
        channel = future.channel();
        future.addListener(f -> {
            if (f.isSuccess()) {
                GatewayWorkPool.init(websocketServerConfig.getWorkThreadSize() ,websocketServerConfig.getWorkQueueSize());
                log.info("webSocketServer have success bind to " + websocketServerConfig.getPort());
            } else {
                log.error("webSocketServer fail bind to " + websocketServerConfig.getPort());
                throw new ApplicationStartException("Server start fail !", f.cause());
            }

        });

        channel.closeFuture().addListener(f -> {

        });
//        future.channel().closeFuture().sync();
    }

    @PreDestroy
    public void destroy() {
        log.info("destroy webSocketServer ...");
        // 释放线程池资源
        if (channel != null) {
            channel.close();
        }
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        GatewayWorkPool.shutdown();
        log.info("destroy  webSocketServer complete.");
    }
}
